home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #27 (Dec 87) / c daisy printer driver / XPrint.c < prev   
C/C++ Source or Header  |  1987-10-24  |  10KB  |  418 lines

  1.  
  2. /*
  3.  * XPrint.c.  C code for a printer driver for daisy-wheel printers
  4.  * for the Macintosh.
  5.  * Earle R. Horton.  August 17, 1987
  6.  * LightspeedC source.
  7.  * Set the project type to Device Driver, ID #2.
  8.  * Run RMaker to put the resources in the printer resource file.
  9.  * Install with Chooser.
  10.  */
  11. #include <WindowMgr.h>    /* includes QuickDraw.h, MacTypes.h */
  12. #include <EventMgr.h>
  13. #include <DialogMgr.h>
  14. #include <SerialDvr.h>    
  15. #include <FontMgr.h>
  16. #include <HFS.h>
  17. #include <asm.h>
  18. #define  DRIVER_MODULE
  19. #include "prglobals.h"
  20. /*
  21.  * LightspeedC doesn't provide these as InLines.  To save space, I provide
  22.  * my own routines.  This way, I get around having to link in MacTraps.
  23.  */
  24. int    HNoPurge();
  25. int    HPurge();
  26. int    HLock();
  27. int    CloseDriver();
  28.  
  29. int    checkabort();
  30.  
  31. /* Useful constants */
  32. #define OPEN    0
  33. #define PRIME    1
  34. #define CONTROL    2
  35. #define STATUS    3
  36. #define CLOSE    4
  37.  
  38.  
  39. #define    SERRESET    8
  40. #define    SERSHAKE    10
  41.  
  42.  
  43. #define XONCR    ((char)17)
  44. #define XOFFCR    ((char)19)
  45. #define RESFILEID    (-8192)
  46. #define    PACKID        (-4080)    
  47.  
  48. main(p, d, n)
  49. PrParam *p;        /*  ==> parameter block  */
  50. DCtlPtr d;        /*  ==> device control entry  */
  51. int n;            /*  entry point selector  */
  52.  
  53. {
  54. /* Check to make sure our data area was allocated.  It may not have been 
  55.  * if we were opened with a low-level open or even a device manager PBOpen() 
  56.  * and our printer resource file was not opened.  Note that we cannot use 
  57.  * any of LightspeedC's "global" variables until after we get our storage 
  58.  * from the resource file and lock it down, making A4 point to it.  This 
  59.  * probably does the same thing that the prolog code attempts to do with
  60.  * the original 'DATA' resource created by LightspeedC.
  61.  */
  62. int    i;
  63. Handle    storage;
  64.     if(d->dCtlStorage == nil && n != CLOSE){
  65.         if (openprinterfile(d) == -1){
  66.                     PrintErr = ResError();
  67.                     CloseDriver(d->dCtlRefNum);
  68.                     return(-1);
  69.            }
  70.     }
  71.     HLock(d->dCtlStorage);
  72.     storage = d->dCtlStorage;
  73.     asm{
  74.         movea.l    storage,a0    ;; LightspeedC uses A4 as the base
  75.         movea.l    (a0),a4        ;; for driver globals.
  76.     }
  77.     if (d->dCtlStorage != nil) switch (n){    /*  dispatch  */
  78.  
  79.         case OPEN:            /*  open  */
  80.         openprinterfile(d);
  81.         if((settings = (Pfg)(GetResource('Stng',RESFILEID))) == nil ||
  82.             GetResource('STR#',PACKID) == nil){
  83.             CloseDriver(d->dCtlRefNum);
  84.             return(-1);        /* Can't run without these. */
  85.         }
  86.         LoadResource(settings);
  87.         HNoPurge(settings);
  88.         SetControlStrings();
  89.         SPopen();
  90.             HPurge(settings);
  91.             settings = nil;
  92.         prpb.ioNamePtr = prname;
  93.         break;
  94.  
  95.         case PRIME:    /* For read/write calls, not applicable here. */
  96.             break;
  97.  
  98.         case CONTROL:        /*  control  */
  99.         switch (p->csCode){    /* Device Control Call */
  100.         /* p->csCode gives opcode, and we switch on */
  101.         /* it to perform low-level Printing calls */
  102.         case iPrBitsCtl:    /* Send a bitmap to the printer (NA). */
  103.             break;
  104.         case iPrIOCtl:        /* Text streaming. */
  105.             iopb.ioParam.ioBuffer = (Ptr)p->lParam1;
  106.             iopb.ioParam.ioReqCount = p->lParam2;
  107.             asm{
  108.                 lea    iopb,a0
  109.                 PBWrite
  110.             }
  111.             break;
  112.         case iPrEvtCtl:        /* Screen printing. (cmd-shift 4, NA.)*/
  113.             break;
  114.         case iPrDevCtl:        /* CR, LF, FF, etc. */
  115.             devicecontrol(p->lParam1);
  116.             break;
  117.         case iFMgrCtl:
  118. /* Font manager font table modify request.  p->lParam1 is a pointer to 
  119.  * an FMInput record.  (IM says we get an FMOutPtr here, but MacsBug says 
  120.  * we get a pointer to an FMInput.  I go with MacsBug.)  In addition, the
  121.  * integer following p->lParam1 contains our driver reference number and 
  122.  * a private byte we can use internally.
  123.  * The application first does something to determine the characteristics of 
  124.  * fonts in our printing GrafPort.  The Font Manager calls our status 
  125.  * routine with csParam = 8 and we give it a "font characterization table".
  126.  * The Font Manager selects a font, and calls our control routine to confirm
  127.  * the choice.  We change it to Monaco 9, horizontal scaling.  If you need to 
  128.  * support proportional fonts, then you have to do something about it here
  129.  * and in the printing code, too.  Good luck.
  130.  */
  131.             {
  132.             FMInput *fontset;
  133.                  fontset = (FMInput *)p->lParam1;
  134.                  fontset->family = monaco;
  135.                  fontset->face = 0;
  136.                  fontset->needBits = 0;
  137.                  fontset->numer = noscale;
  138.                  fontset->denom = noscale;
  139.                  if(fontset->device == IDEV10){
  140.                      fontset->size = 10;
  141.                      fontset->numer.h = 7;
  142.                      fontset->denom.h = 6;
  143.                  }
  144.                  else if(fontset->device == IDEV15){
  145.                      fontset->size = 7;
  146.                      fontset->numer.h = 5;
  147.                      fontset->denom.h = 6;
  148.                  }
  149.                  else fontset->size = 9;
  150.             }
  151.             break;
  152.         default:
  153.             break;
  154.         }
  155.         break;
  156.         case STATUS:
  157.         switch (p->csCode){    /* Device Status Call */
  158.         /* p->csCode gives opcode, and we switch on */
  159.         /* it to perform low-level Printing calls */
  160.         case iFMgrCtl:
  161. /* Font manager font table request.  Help out the Font Manager.
  162. /* p->lParam1 is a pointer to an area in memory in which to put a copy
  163.  * of the information describing our font capabilities.  p->lParam2 has
  164.  * an integer in its high order word which contains the "resolution" to use,
  165.  * set in a style dialog with the user.  We say we have different horizontal
  166.  * resolutions, based on the number of characters per inch used.  I believe 
  167.  * this gets called whenever the application does a GetFontInfo() or
  168.  * StringWidth() or whatever for the first time in one of our printing
  169.  * GrafPorts.  Possibly also when the application tries to change the 
  170.  * font style.
  171.  */
  172.             *((fontab *)p->lParam1) = myfonts;
  173.             break;
  174.         default:
  175.             break;
  176.         }
  177.         break;
  178.         case CLOSE:        /*  close  */
  179.             if(storage != nil){
  180.                 HPurge(storage);
  181.                 d->dCtlStorage = nil;
  182.             }
  183.         break;
  184.     }
  185.     
  186.     /*  done  */
  187.     
  188.     return(0);
  189. }
  190. SPopen()        /* Open the serial driver and configure it. */
  191.             /* Use low-level ROM routines. */
  192. {
  193. ParmBlkPtr    pb;
  194. int        serconfig;
  195.     pb = &iopb;
  196.     switch (pport){        /* get the correct port */
  197.         case 0:        /* modem port */
  198.             if(!phone) {
  199.                 prinit("\p.AOut");
  200.                 phone = TRUE;
  201.             }
  202.             drivernum = AoutRefNum;
  203.             break;
  204.         case 1:        /* printer port */
  205.             if(!printer) {
  206.                 prinit("\p.BOut");
  207.                 printer = TRUE;
  208.             }
  209.             drivernum = BoutRefNum;
  210.             break;
  211.         }
  212.     /* set up the io parameter block for writing to the serial driver. */
  213.     /* a control call resets the baud rate */
  214.     pb->ioParam.ioRefNum = drivernum;
  215.     pb->ioParam.ioCompletion = nil;
  216.     ((cntrlParam *)pb)->csCode = SERRESET;
  217.     serconfig = data8 + noParity + stop20;
  218.     serconfig += mybauds[pbaud].rate;
  219.     ((cntrlParam*)pb)->csParam[0] = serconfig;
  220.     asm{
  221.             move.l    pb,a0
  222.            PBControl
  223.     }
  224. #define shake     ((SerShk*)&((cntrlParam*)pb)->csParam[0])
  225.     shake->errs = FALSE;
  226.     shake->evts = FALSE;
  227.     shake->fDTR = FALSE;
  228.     shake->fInX = FALSE;
  229.     if(XonXoff && (theWorld.machineType >= envMachUnknown)){
  230.             shake->fXOn = TRUE;
  231.             shake->fCTS = FALSE;
  232.             shake->xOn = XONCR;
  233.             shake->xOff = XOFFCR;
  234.     }
  235.     else {
  236.             shake->fXOn = FALSE;
  237.             shake->fCTS = TRUE;
  238.     }
  239.     ((cntrlParam *)pb)->csCode = SERSHAKE;
  240.     asm{
  241.             move.l    pb,a0
  242.            PBControl
  243.     }
  244.         
  245. #undef shake
  246.     pb->ioParam.ioPosMode = 0;
  247.     pb->ioParam.ioPosOffset = 0;
  248. }
  249.  
  250. prinit(name)                    /* Open a driver by name. */
  251. StringPtr name;    /* ROM serial driver?  RAM serial driver?  Who cares? */
  252. {
  253.     iopb.ioParam.ioNamePtr = name;
  254.     iopb.ioParam.ioCompletion = nil;
  255.     iopb.ioParam.ioPermssn = 0;
  256.     asm{
  257.         lea    iopb,a0
  258.         PBOpen
  259.     }
  260. }
  261. /*
  262.  * Set the printer control strings based on what is in our STR# resource.
  263.  */
  264. SetControlStrings()
  265. {
  266. unsigned char    *strptr;
  267. unsigned char    **mystrings;
  268.  
  269.     mystrings = (unsigned char **)GetResource('STR#',PACKID);
  270.     if(mystrings != nil){
  271.         LoadResource(mystrings);
  272.         copystr(  (strptr = (*mystrings)+2)  , prlfstr);
  273.         copystr(  (strptr += (*strptr) + 1)  , prinitstr);
  274.         copystr(  (strptr += (*strptr) + 1)  , prtopstr);
  275.         copystr(  (strptr += (*strptr) + 1)  , preopstr);
  276.         copystr(  (strptr += (*strptr) + 1)  , preofstr);
  277.         decode(prlfstr);
  278.         decode(prinitstr);
  279.         decode(prtopstr);
  280.         decode(preopstr);
  281.         decode(preofstr);
  282.     }
  283. }
  284. decode(str)
  285. unsigned char *str;
  286. {
  287. register unsigned char i,count;
  288.     count = 1;
  289.     for(i=0;str[0]-i++;){
  290.         if (str[i] == '^') str[count] = 31 & str[++i];
  291.         else str[count] = str[i];
  292.         count++;
  293.     }
  294.     str[0] = count - 1;
  295. }
  296. /*
  297.  * This is for copying PASCAL strings.  Simple.
  298.  */
  299. copystr(src,dst)
  300. unsigned char *src,*dst;
  301. {
  302.     asm{
  303.         clr.l    d0
  304.         move.l    src,a0
  305.         move.l    dst,a1
  306.         move.b    (a0),d0
  307.     loop:
  308.         move.b    (a0)+,(a1)+
  309.         dbra    d0,@loop
  310.     }
  311. }
  312. devicecontrol(code)    /* Handle printer device control calls. */
  313. long    code;
  314. {
  315.     switch(code){
  316.         case lPrReset:
  317.             printstring(prinitstr);
  318.             break;
  319.         case lPrPageEnd:
  320.             printstring(preopstr);
  321.             break;
  322.         case lPrLineFeed:
  323.         case lPrLFSixth:
  324.         case lPrLFEighth:
  325.             printstring(prlfstr);
  326.             break;
  327.         default:        /* Unknown parameter. */
  328.             break;
  329.     }
  330. }
  331. printstring(string)    /* Send a printer control string to the */
  332.             /* serial driver. */
  333. unsigned char    *string;        
  334. {
  335.     iopb.ioParam.ioBuffer = (Ptr)(string+1);
  336.     iopb.ioParam.ioReqCount = (long)(string[0]);
  337.     asm{
  338.         lea    iopb,a0
  339.         PBWrite
  340.     }
  341. }
  342. /* Find the system folder, and open our printer resource file, if we can.
  343.  * Fill in a global SysEnvRec, which might be useful for other stuff. 
  344.  */
  345. int openprinterfile(d)
  346. DCtlPtr d;
  347. {            
  348. SysEnvRec    myWorld;
  349. StringHandle     ourname;
  350. int        therefnum;
  351. Handle        storage;
  352.  
  353.     if(d->dCtlStorage != nil) 
  354.         HPurge(d->dCtlStorage);
  355.     ourname = (StringHandle)GetResource('STR ',0xE000);
  356.     LoadResource(ourname);
  357.     HNoPurge(ourname);        /* Get printer resource file name. */
  358.     HLock(ourname);
  359.     SysEnvirons(1,&myWorld);
  360.     if(myWorld.machineType >= envMachUnknown)
  361.         therefnum = OpenRFPerm(*ourname,myWorld.sysVRefNum,fsCurPerm);
  362.     else
  363.         therefnum = OpenResFile(*ourname);
  364.     HPurge(ourname);
  365.     if (therefnum != -1){
  366.         d->dCtlStorage = (Handle)GetResource('PREC',RESFILEID);
  367.         if(d->dCtlStorage != nil){
  368.             LoadResource(d->dCtlStorage);
  369.             DetachResource(d->dCtlStorage);
  370.             HNoPurge(d->dCtlStorage);
  371.             HLock(d->dCtlStorage);
  372.             storage = d->dCtlStorage;
  373.             asm{
  374.                 movea.l storage,a0    ;; LightspeedC uses A4
  375.                 movea.l (a0),a4        ;; for driver globals.
  376.             }
  377.             theWorld = myWorld;
  378.         }
  379.     }
  380.     return (therefnum);
  381. }
  382. int HNoPurge(c)
  383. char *c;
  384. {
  385.     asm{
  386.         move.l    c,a0
  387.         HNoPurge
  388.     }
  389. }
  390. int HPurge(c)
  391. char *c;
  392. {
  393.     asm{
  394.         move.l    c,a0
  395.         HPurge
  396.     }
  397. }
  398. int HLock(c)
  399. char *c;
  400. {
  401.     asm{
  402.         move.l    c,a0
  403.         HLock
  404.     }
  405. }
  406. int    CloseDriver(refnum)
  407. int    refnum;
  408. {
  409. ParamBlockRec    closepb;
  410.     asm{
  411.         lea    closepb,a0
  412.         move.w    refnum,24(a0)
  413.         clr.l    12(a0)
  414.         PBClose
  415.         move.w    16(a0),d0
  416.     }
  417. }
  418.